package com.game.Maze.Objects;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import com.game.Maze.Util.WorldSide;

/**
 * Объект, который содержит информацию о комнате лабиринта
 * 
 */
public class Room implements IRoom
{
  // Комнаты с которыми соприкасается данная комната
  private HashMap<WorldSide, Room> m_Rooms = new HashMap<WorldSide, Room>();

  // Стены или проходы окружающие данную комнату
  private HashMap<WorldSide, Passage> m_Passages = new HashMap<WorldSide, Passage>();

  // Тип комнаты
  private RoomType m_Type = RoomType.Unused;

  // Сторона выхода из лабиринта (для комнаты типа RoomType.Exit)
  private WorldSide m_ExitSide = WorldSide.None;
  
  // Игрок видит объект
  // TODO сделать false
  private boolean m_Visible = true; 

  /**
   * Создает комнату
   */
  public Room()
  {
    m_Passages.put(WorldSide.North, new Passage(this, WorldSide.North));
    m_Passages.put(WorldSide.East, new Passage(this, WorldSide.East));
    m_Passages.put(WorldSide.South, new Passage(this, WorldSide.South));
    m_Passages.put(WorldSide.West, new Passage(this, WorldSide.West));
  }

  /**
   * Помечает комнату как используемую в лабиринте
   */
  public void setUsed()
  {
    m_Type = RoomType.Maze;
  }
  
  /**
   * Устанавливает комнату которая соприкасается с данной в указанном направлении
   * 
   * @param aSide направление
   * @param aRoom комната
   */
  public void setRoomBySide(WorldSide aSide, Room aRoom)
  {
    m_Rooms.put(aSide, aRoom);
  }

  /**
   * @return сторону выхода из лабиринта
   */
  public WorldSide exitSide()
  {
    return m_ExitSide;
  }

  /**
   * @return комнату в заданном направлении или null, если комнаты нет
   */
  public Room roomBySide(WorldSide aSide)
  {
    if (m_Rooms.containsKey(aSide))
      return m_Rooms.get(aSide);
    else
      return null;
  }

  /**
   * @param aSide заданное направление
   * @return проход/стену в заданном направлении
   */
  public Passage passageBySide(WorldSide aSide)
  {
    if (m_Passages.containsKey(aSide))
      return m_Passages.get(aSide);
    else
      return null;
  }
  
  /**
   * @return возвращает истину, если комната используется в лабиринте
   */
  public boolean isUsed()
  {
    return (RoomType.Unused != m_Type);
  }

  /**
   * Устанавливает сторону выхода из лабиринта
   * и помечает комнату как выход
   * 
   * @param aExitSide сторона выхода
   */
  public void markAsExit(WorldSide aExitSide)
  {
    m_ExitSide = aExitSide;
  }
  
  /**
   * Создает вместо стены проход в указанном направлении
   * @param aPassageSide направление в котором создается проход
   */
  public void makePassageBySide(WorldSide aPassageSide)
  {
    /* TODO Нужно сделать так, чтобы проход связывал две комнаты
     * потому что сейчас для смежных комнат хранятся свои стены/проходы
     * и приходится реализовывать сложную логику при создании проходов
     */
    
    // Получаем комнату с другой стороны прохода
    Room passageRoom = roomBySide(aPassageSide);

    // Если там комнаты нет, то некуда делать проход
    if (null == passageRoom)
      return;
    
    // Создаем проход
    passageBySide(aPassageSide).makePassage();
    
    // Определяем комнату с другой стороны прохода
    WorldSide anotherSide = WorldSide.oppositeSide(aPassageSide);
    
    // Создаем проход в стене у смежной комнаты
    Passage anotherSidePassage = passageRoom.passageBySide(anotherSide); 
    
    if (anotherSidePassage.isWall())
      anotherSidePassage.makePassage();
      
  }

  /**
   * Возвращает список всех стен для комнаты.
   * @return список всех стен для комнаты
   */
  public Collection<Passage> getAllWalls()
  {
    ArrayList<Passage> walls = new ArrayList<Passage>();
    Iterator<Passage> passages = m_Passages.values().iterator();
    Passage passage;
    
    while (passages.hasNext())
    {
      passage = passages.next();
      
      if (passage.isWall())
        walls.add(passage);
    }
    
    return walls;    
  }

  @Override
  public boolean hasWall(WorldSide aSide)
  {
    Passage passage = passageBySide(aSide);
    
    if (null == passage)
      return true;
    else
      return passage.isWall();
  }

  @Override
  public boolean isExitSide(WorldSide aSide)
  {
    return (m_ExitSide == aSide);
  }

  public boolean isVisible()
  {
    return m_Visible;
  }

  public void makeVisible()
  {
    m_Visible = true;    
  }

  @Override
  public boolean isWallVisible(WorldSide aSide)
  {
    return passageBySide(aSide).isVisible();
  }
}
